﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.Xml;
using System.IO;


namespace FactoryInstaller {
    [RunInstaller(true)]
    public partial class FactoryInstaller : Installer {


        DataBaseCreationForm dbWizard;
        
        public FactoryInstaller() {
            InitializeComponent();


        }


        #region IIs Authetication stuff

        public const int SecuritySettingAllowAnonymous = 1;
        public const int SecuritySettingAllowBasic = 2;
        public const int SecuritySettingAllowNTLM = 4;

        private void SetIIsAuthetication() {

            System.DirectoryServices.DirectoryEntry entry = GetIIsSiteEntry();
            
            
            // define the security flag
            int securityType = 0;

            // allow anonymous
            if (!UseWindowsAuthentication)
                securityType = (securityType | SecuritySettingAllowAnonymous);           
            
            // allow NTLM
            if(UseWindowsAuthentication)
                securityType = (securityType | SecuritySettingAllowNTLM);

            // set security and commit            
            entry.Properties["AuthFlags"].Clear();
            entry.Properties["AuthFlags"].Add(securityType);
            
            
            entry.CommitChanges();

            
        }

        #endregion

        private System.DirectoryServices.DirectoryEntry GetIIsSiteEntry() {            
            string targetSite = Context.Parameters["TARGETSITE"];
            if (targetSite.StartsWith("/LM/"))
                targetSite = targetSite.Substring(4);
            return new System.DirectoryServices.DirectoryEntry("IIS://LocalHost/" + targetSite);            
        }


        private void SetLogFilePermissions() {

             
            try {

                System.Security.AccessControl.FileSecurity security = File.GetAccessControl(LogFilename);

                System.Security.Principal.SecurityIdentifier si = new System.Security.Principal.SecurityIdentifier(
                    System.Security.Principal.WellKnownSidType.NetworkServiceSid, null);


                System.Security.AccessControl.FileSystemAccessRule access =
                    new System.Security.AccessControl.FileSystemAccessRule(
                        si.Translate(typeof(System.Security.Principal.NTAccount)),
                        System.Security.AccessControl.FileSystemRights.Modify,
                        System.Security.AccessControl.AccessControlType.Allow);

                security.AddAccessRule(access);

                File.SetAccessControl(LogFilename, security);
            }
            catch (Exception ) { }
        }
        
        

        protected string WebConfigFilename {
            get {
                return System.IO.Path.Combine(Context.Parameters["TARGETDIR"], "Web.config");
            }
        }

        protected string LogFilename {
            get {
                return System.IO.Path.Combine(Context.Parameters["TARGETDIR"], "App_Data\\Log\\factorylog.txt");
            }
        }

      


        public override void Rollback(IDictionary savedState) {
            dbWizard.DropDatabase();
            base.Rollback(savedState);            
        }
        

        

        public override void Install(IDictionary stateSaver) {

            
   
            ValidateInfo();
                        
            base.Install(stateSaver);

            StartDataBaseWizard();

            SetWebConfig();

            SetLogFilePermissions();

            
            SetIIsAuthetication();

            if(dbWizard.accessKey!=null)
                stateSaver.Add("accessKey", dbWizard.accessKey);
                   
        }

        public override void Commit(IDictionary savedState) {
            base.Commit(savedState);

            System.Diagnostics.Process p = new System.Diagnostics.Process();

            string serverHomePage = SiteName + Context.Parameters["TARGETVDIR"];
            if (savedState.Contains("accessKey"))
                serverHomePage = serverHomePage + "/Default.aspx?adminAccessKey=" + savedState["accessKey"].ToString();

            System.Diagnostics.ProcessStartInfo pInfo = new System.Diagnostics.ProcessStartInfo(serverHomePage);
            pInfo.UseShellExecute = true;
            p.StartInfo = pInfo;
            p.Start();
            
        }

        private void ValidateInfo() {

            if (String.IsNullOrEmpty(Context.Parameters["ORGANIZATION_NAME"]))
                throw new InstallException("Organization Name should be provided.");

           



        }

        private string SiteName {
            get {
                System.DirectoryServices.DirectoryEntry entry = GetIIsSiteEntry();

                if (entry == null)
                    return "http://localhost";

                System.DirectoryServices.PropertyValueCollection pvc = entry.Properties["ServerBindings"];
                if(pvc.Count==0)
                    return "http://localhost/";
                
                string[] Bits = pvc[0].ToString().Split(':');
                string IPAddress = Bits[0];
                string TCPIPPort = Bits[1];
                string hostHeader = Bits[2];

                if (hostHeader.Length == 0)
                    hostHeader = "localhost";


                return "http://" + hostHeader + ":" + TCPIPPort + "/";
                
                
            }
        }

        string connectionString;

        private bool UseWindowsAuthentication {
            get {
                return Context.Parameters["AUTHENTICATION_METHOD"] == "1";
            }
        }

        private void StartDataBaseWizard() {
            
            dbWizard = new DataBaseCreationForm(Context.Parameters["TARGETDIR"] + "\\App_Data\\DBSCRIPTS", UseWindowsAuthentication);            
            dbWizard.ShowDialog();
            
            connectionString = dbWizard.ConnectionStringForApplication;
        }

        private void SetWebConfig() {

            if(!dbWizard.wasCanceled)
                SetApplicationValue("BadHabit.Factory.Data.Properties.Settings.FactoryConnectionString", connectionString);

            SetApplicationValue("BadHabit.Factory.Properties.Settings.SMTPServerAddress", Context.Parameters["SMTP_SERVER"]);
            SetApplicationValue("BadHabit.Factory.Properties.Settings.FactoryEmailAccount", Context.Parameters["EMAIL_ACCOUNT"]);
            SetApplicationValue("BadHabit.Factory.Properties.Settings.FactoryCompanyName", Context.Parameters["ORGANIZATION_NAME"]);
            if(!String.IsNullOrEmpty(Context.Parameters["MSEXCHANGEPATH"])) 
                SetApplicationValue("BadHabit.Factory.Properties.Settings.MSExchangePath", Context.Parameters["MSEXCHANGEPATH"]);
            SetApplicationValue("BadHabit.Factory.Properties.Settings.DocumentRepositoryPath", Context.Parameters["PROJECT_NETWORK_FOLDER"]);
        }



        private string GetApplicationValue(string key) {
            XmlDocument doc = new XmlDocument();
            doc.Load(WebConfigFilename);


            foreach (XmlNode node in doc["configuration"]["applicationSettings"]) {
                if (node.Name == "add")
                    if (node.Attributes.GetNamedItem("key").Value == key) {
                        return node.Attributes.GetNamedItem("value").Value;
                    }
            }
            foreach (XmlNode node in doc["configuration"]["connectionStrings"]) {
                if (node.Name == "add")
                    if (node.Attributes.GetNamedItem("name").Value == key) {
                        return node.Attributes.GetNamedItem("connectionString").Value;
                    }
            }

            foreach (XmlNode node in doc["configuration"]["applicationSettings"]["BadHabit.Factory.Properties.Settings"]) {
                if (node.Name == "setting")
                    if (("BadHabit.Factory.Properties.Settings." + node.Attributes.GetNamedItem("name").Value) == key) {
                        return node["value"].InnerText;
                    }
            }

            throw new Exception("Section was '" + key + "' not found at config file.");




        }

        private void SetApplicationValue(string key, string value) {

            if (key == null)
                throw new Exception("Key can not be null");
            
            XmlDocument doc = new XmlDocument();
            doc.Load(WebConfigFilename);

            foreach (XmlNode node in doc["configuration"]["applicationSettings"]) {
                if (node.Name == "add")
                    if (node.Attributes.GetNamedItem("key").Value == key) {
                        node.Attributes.GetNamedItem("value").Value = value;
                        doc.Save(WebConfigFilename);
                        return;
                    }
            }
            foreach (XmlNode node in doc["configuration"]["connectionStrings"]) {
                if (node.Name == "add")
                    if (node.Attributes.GetNamedItem("name").Value == key) {
                        node.Attributes.GetNamedItem("connectionString").Value = value;
                        doc.Save(WebConfigFilename);
                        return;
                    }
            }
            foreach (XmlNode node in doc["configuration"]["applicationSettings"]["BadHabit.Factory.Properties.Settings"]) {
                if (node.Name == "setting")
                    if (("BadHabit.Factory.Properties.Settings." + node.Attributes.GetNamedItem("name").Value) == key) {
                        node["value"].InnerText = value;
                        doc.Save(WebConfigFilename);
                        return;
                    }
            }

            throw new Exception("Section '" + key + "' not found at config file.");


        }


       


       

    }
}
